using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.IO;
using System.Xml;

namespace Woz
{
    /// <summary>
    /// a screen thumbnail basically contains a thumbnail of the screen
    /// </summary>
    public class ScreenThumbnail : UserControl
    {
        /// <summary>
        /// static constructor to initialize all of the static members
        /// </summary>
        static ScreenThumbnail()
        {
            // calculate the thumbnail size
            Size thumbnailSize = new Size(Woz.StaticVariables.Instance.ThumbnailSize.Width + Woz.StaticVariables.Instance.ThumbnailMargin.Width * 2, Woz.StaticVariables.Instance.ThumbnailSize.Height + Woz.StaticVariables.Instance.ThumbnailMargin.Height * 3 + 17);

            // create the background image for selected thumbnails
            sSelectedImage = new Bitmap(thumbnailSize.Width, thumbnailSize.Height);
            using (Graphics graphics = Graphics.FromImage(sSelectedImage))
            {
                graphics.Clear(Color.Orange);
                graphics.FillRectangle(new SolidBrush(Color.FromArgb(255, 212, 139)), 1, 1, thumbnailSize.Width - 2, thumbnailSize.Height - 2);
            }

            // also initialize the textbox
            sRenamingTextbox = new TextBox();
            sRenamingTextbox.TextAlign = HorizontalAlignment.Center;
            sRenamingTextbox.Size = new Size(Woz.StaticVariables.Instance.ThumbnailSize.Width, 17);
            sRenamingTextbox.KeyDown += new KeyEventHandler(Woz.ScreenThumbnail.OnRenameKeyDown);
            sRenamingTextbox.Leave += new EventHandler(Woz.ScreenThumbnail.OnRenameLeave);
        }


        /// <summary>
        /// represents a screen thumbnail
        /// </summary>
        /// <param name="pScreen">the screen whose thumbnail we need</param>
        internal ScreenThumbnail(Woz.Screen pScreen)
        {
            // set the desired index
            this.mDesiredIndex = -1;

            // set the screen
            this.mScreen = pScreen;

            // create the overlay
            this.mOverlay = new PictureBox();

            // create the picturebox
            this.mPicture = new PictureBox();

            // create the label
            this.mLabel = new Label();

            // initialize the usercontrol and add the picturebox and label
            base.SuspendLayout();

            // initialize the overlay
            this.mOverlay.BackColor = Color.Green;
            this.mOverlay.BorderStyle = BorderStyle.FixedSingle;
            this.mOverlay.Location = new Point(Woz.StaticVariables.Instance.ThumbnailSize.Width / 2 - 16, 0);
            this.mOverlay.Size = new Size(32, 32);
            //this.mOverlay.Cursor = Woz.ResourceManager.Instance.Cursors["sizeall"];
            this.mOverlay.Cursor = Cursors.SizeAll;
            this.mOverlay.Image = new Bitmap(32, 32);
            this.mOverlay.TabIndex = 2;
            this.mOverlay.TabStop = false;

            // initialize the picturebox
            this.mPicture.BackColor = Color.White;
            this.mPicture.BorderStyle = BorderStyle.FixedSingle;
            this.mPicture.Location = new Point(Woz.StaticVariables.Instance.ThumbnailMargin.Width, Woz.StaticVariables.Instance.ThumbnailMargin.Height);
            this.mPicture.Size = Woz.StaticVariables.Instance.ThumbnailSize;
            this.mPicture.MouseDown += new MouseEventHandler(this.OnMouseDown);
            this.mPicture.Click += new EventHandler(this.OnClick);
            this.mPicture.Image = pScreen.Thumbnail;
            this.mPicture.TabIndex = 1;
            this.mPicture.TabStop = false;

            // initialize the label
            this.mLabel.Location = new Point(Woz.StaticVariables.Instance.ThumbnailMargin.Width, Woz.StaticVariables.Instance.ThumbnailSize.Height + Woz.StaticVariables.Instance.ThumbnailMargin.Height * 2);
            this.mLabel.Size = new Size(Woz.StaticVariables.Instance.ThumbnailSize.Width, 17);
            this.mLabel.Text = pScreen.Name;
            this.mLabel.TextAlign = ContentAlignment.MiddleCenter;
            this.mLabel.MouseDown += new MouseEventHandler(this.OnMouseDown);
            this.mLabel.Click += new EventHandler(this.OnClick);
            this.mLabel.DoubleClick += new EventHandler(this.OnDblClick);

            // initialize the usercontrol
            base.BackColor = Color.Transparent;
            base.Size = sSelectedImage.Size;
            base.MouseDown += new MouseEventHandler(this.OnMouseDown);
            base.Click += new EventHandler(this.OnClick);

            // add the picturebox and label
            base.Controls.Add(this.mOverlay);
            base.Controls.Add(this.mPicture);
            base.Controls.Add(this.mLabel);

            // we are done here
            base.ResumeLayout(false);
        }

        /// <summary>
        /// gets or sets the index of this screen thumbnail
        /// </summary>
        public int Index
        {
            get
            {
                if (this.mScreen.SliderThumbnail.Parent != null)
                {
                    return this.mScreen.SliderThumbnail.Parent.Controls.IndexOf(this.mScreen.SliderThumbnail);
                }

                return -1;
            }

            set
            {
                if (this.mScreen.SliderThumbnail.Parent != null)
                {
                    this.mScreen.SliderThumbnail.Parent.Controls.SetChildIndex(this.mScreen.SliderThumbnail, value);
                    this.mDesiredIndex = value;
                }
            }
        }

        /// <summary>
        /// gets or sets the desired index
        /// </summary>
        public int DesiredIndex
        {
            get
            {
                return this.mDesiredIndex;
            }

            set
            {
                this.mDesiredIndex = value;
            }
        }

        /// <summary>
        /// renames the screen associated with the given screen thumbnail
        /// </summary>
        /// <param name="pScreenThumbnail">the screen thumbnail to rename</param>
        /// <param name="pNewName">the new name to give to the screen thumbnail</param>
        /// <returns>true if rename was successful false otherwise</returns>
        public static bool RenameScreen(Woz.ScreenThumbnail pScreenThumbnail, string pNewName)
        {
            //// make sure the new name is not already being used
            //foreach (Woz.Screen screen in Woz.ScreenManager.Instance.Screens)
            //{
            //    // if the names are the same there is no reason to rename
            //    if (screen.Name.ToLower() == pNewName.ToLower())
            //    {
            //        return false;
            //    }
            //}

            // set the label text of the screen thumbnail slider
            pScreenThumbnail.mScreen.SliderThumbnail.mLabel.Text = pNewName;

            // set the label text of the edit screen transitions mode thumbnail
            pScreenThumbnail.mScreen.TransitionsThumbnail.mLabel.Text = pNewName;

            // set the screen name to the new name
            pScreenThumbnail.mScreen.Name = pNewName;

            // return success
            return true;
        }

        /// <summary>
        /// the screen associated with this screen thumbnail
        /// </summary>
        public Woz.Screen Screen
        {
            get
            {
                return this.mScreen;
            }
        }

        /// <summary>
        /// gets or sets whether the screen thumbnail can be renamed
        /// </summary>
        public bool Readonly
        {
            get
            {
                return this.mReadonly;
            }
            set
            {
                this.mReadonly = value;
            }
        }

        /// <summary>
        /// gets the label of this screen thumbanil control
        /// </summary>
        internal Label Label
        {
            get
            {
                return this.mLabel;
            }
        }

        /// <summary>
        /// refresh the thumbnail image
        /// </summary>
        public void RefreshThumbnail()
        {
            this.mPicture.Invalidate();
        }

        /// <summary>
        /// selects this screen thumbnail
        /// </summary>
        public new void Select()
        {
            // set the background image of the control to our selection image
            this.BackgroundImage = sSelectedImage;

            // call the internal select
            base.Select();
        }

        /// <summary>
        /// deselects this screen thumbnail
        /// </summary>
        public void Deselect()
        {
            // set the background image to nothing
            this.BackgroundImage = null;
        }

        /// <summary>
        /// handles mouse down events
        /// </summary>
        /// <param name="pSender">the sender of the event</param>
        /// <param name="pEventArgs">the mouse event args associated</param>
        private void OnMouseDown(object pSender, MouseEventArgs pEventArgs)
        {
            // detach the textbox
            Woz.ScreenThumbnail.DetachTextbox(false);

            // fire the mouse down event
            if (this.MouseDown != null)
            {
                this.MouseDown.Invoke(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// handles the click
        /// </summary>
        /// <param name="pSender">the sender of the event</param>
        /// <param name="pEventArgs">the event args associated</param>
        private void OnClick(object pSender, EventArgs pEventArgs)
        {
            // detach the textbox
            Woz.ScreenThumbnail.DetachTextbox(false);

            // fire the click event
            if (this.Click != null)
            {
                this.Click.Invoke(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// handles the double click
        /// </summary>
        /// <param name="pSender">the sender of the event</param>
        /// <param name="pEventArgs">the event args associated</param>
        private void OnDblClick(object pSender, EventArgs pEventArgs)
        {
            // attach the textbox
            Woz.ScreenThumbnail.AttachTextbox(this);
        }

        /// <summary>
        /// attach a textbox to the screen thumbnail control
        /// </summary>
        /// <param name="pThumbnail">the screen thumbnail control to attach a textbox to</param>
        static private void AttachTextbox(Woz.ScreenThumbnail pThumbnail)
        {
            // first if its attached detach it
            if (sRenamingTextbox.Tag != null)
            {
                Woz.ScreenThumbnail.DetachTextbox(true);
            }

            // make sure its not readonly
            if (pThumbnail.Readonly)
            {
                return;
            }

            // attach it
            sRenamingTextbox.Tag = (object)pThumbnail;

            // move it to place
            sRenamingTextbox.Location = new Point(pThumbnail.mLabel.Location.X, pThumbnail.mLabel.Location.Y - 2);

            // set the text
            sRenamingTextbox.Text = pThumbnail.mLabel.Text;

            // remove the label first
            pThumbnail.Controls.Remove(pThumbnail.mLabel);

            // put the textbox where the label used to be
            pThumbnail.Controls.Add(sRenamingTextbox);

            // select the text so the user can edit
            sRenamingTextbox.Select();
        }

        /// <summary>
        /// detach a textbox from the screen thumbnail
        /// </summary>
        /// <param name="pIgnoreChange">specified whether to ignore the change</param>
        static private void DetachTextbox(bool pIgnoreChange)
        {
            // make sure its not detached already
            if (sRenamingTextbox.Tag == null)
            {
                return;
            }

            // save the screen thumbnail
            Woz.ScreenThumbnail screenThumbnail = sRenamingTextbox.Tag as Woz.ScreenThumbnail;

            // get the list of screen names
            List<string> screenNames = new List<string>();
            screenNames.Add("");
            //foreach (Woz.Screen screen in Woz.ScreenManager.Instance.Screens)
            //{
            //    // get all the screens names
            //    screenNames.Add(screen.Name.ToLower());
            //}

            // detach it
            sRenamingTextbox.Tag = null;

            // check to see the new name is not already being used
            if (!pIgnoreChange && !screenNames.Contains(sRenamingTextbox.Text.ToLower()))
            {
                // fire a renamed event
                if (screenThumbnail.Renamed != null)
                {
                    screenThumbnail.Renamed.Invoke(screenThumbnail, sRenamingTextbox.Text);
                }
            }

            // remove the textbox from the thumbnail
            screenThumbnail.Controls.Remove(sRenamingTextbox);

            // add the label to the thumbnail
            screenThumbnail.Controls.Add(screenThumbnail.mLabel);
        }

        /// <summary>
        /// handles when the rename textbox loses focus
        /// </summary>
        /// <param name="pSender">the sender of the event</param>
        /// <param name="pEventArgs">the event args associated</param>
        static private void OnRenameLeave(object pSender, EventArgs pEventArgs)
        {
            // detach the textbox
            Woz.ScreenThumbnail.DetachTextbox(false);
        }

        /// <summary>
        /// handles when the rename textbox recieves a key down
        /// </summary>
        /// <param name="pSender">the sender of the event</param>
        /// <param name="pKeyEventArgs">the event args associated</param>
        static private void OnRenameKeyDown(object pSender, KeyEventArgs pKeyEventArgs)
        {
            // check to see what the key was
            switch (pKeyEventArgs.KeyCode)
            {
                // detach and ignore the change
                case Keys.Escape:
                    Woz.ScreenThumbnail.DetachTextbox(true);
                    break;

                // detach and keep the change
                case Keys.Enter:
                case Keys.Tab:
                    Woz.ScreenThumbnail.DetachTextbox(false);
                    break;

                // do absolutely nothing
                default:
                    break;
            }
        }

        /// <summary>
        /// represents the method that will handle when the screen thumbnail is renamed
        /// </summary>
        /// <param name="pSender">the object that sent this event</param>
        /// <param name="pNewName">the new name of the screen thumbnail</param>
        public delegate void RenameHandler(object pSender, string pNewName);

        /// <summary>
        /// fires when the screen thumbnail gets renamed
        /// </summary>
        public event RenameHandler Renamed;

        /// <summary>
        /// fires when the screen thumbnail is clicked
        /// </summary>
        public new event EventHandler Click;

        /// <summary>
        /// fires when the mouse is down on the screen thumbnail
        /// </summary>
        public new event EventHandler MouseDown;

        /// <summary>
        /// the desired index of this screen thumbnail
        /// </summary>
        private int mDesiredIndex;

        /// <summary>
        /// the screen associated with this screen thumbnail
        /// </summary>
        private Woz.Screen mScreen;

        /// <summary>
        /// the picture box associated with this screen thumbnail
        /// </summary>
        private PictureBox mPicture;

        /// <summary>
        /// an overlay image that is used to move the thumbnail
        /// </summary>
        private PictureBox mOverlay;

        /// <summary>
        /// the label of this screen thumbnail
        /// </summary>
        private Label mLabel;

        /// <summary>
        /// whether or not this thumbnail slider can be renamed
        /// </summary>
        private bool mReadonly;

        /// <summary>
        /// background image that gets applied to selected thumbnails
        /// </summary>
        static private Image sSelectedImage;

        /// <summary>
        /// a textbox to perform renaming on
        /// </summary>
        static private TextBox sRenamingTextbox;
    }
}
